from PySide6.QtWidgets import (QVBoxLayout, QToolBar, QComboBox, QLabel, QSpinBox,
                               QMessageBox, QMenu, QToolButton, QFileDialog,
                               QWidget, QHBoxLayout, QSlider, QCheckBox, QPushButton, QApplication)
from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QAction
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.widgets import SpanSelector
import os
from .base_widget import BaseWidgetMixin
from .display_options_dialog import DisplayOptionsDialog
from .curve_data_dialog import CurveDataDialog

# 设置matplotlib中文字体
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Zen Hei", "Heiti TC"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


class HorizontalVisualizationWidget(QWidget, BaseWidgetMixin):
    """水平数据可视化组件"""

    # 导出信号
    export_requested = Signal(str, pd.DataFrame)

    def __init__(self, parent=None):
        # 显式调用QWidget的构造函数
        super().__init__(parent)#解释: 调用父类的构造函数，确保QWidget的初始化完成

        # 调用Mixin类的初始化方法
        self.setup_ui()
        self.setup_connections()
        self.setup_styles()

        # 当前数据
        self.current_well_name = ""
        self.current_data = None
        self.depth_column = None
        self.current_curve = None
        self.current_display_options = {}

        # 交互状态
        self.zoom_mode = False
        self.pan_mode = False
        self.selection_mode = False
        self.selected_range = None

        # 图表配置
        self.plot_options = {
            "color": "#FF5733",
            "plot_type": "曲线图",
            "line_width": 2,
            "line_style": "-",
            "marker": "None",
            "marker_size": 5,
            "opacity": 1.0,
            "show_grid": True,
            "fill_between": False,
            "normalize": False,
            "log_scale": False,
            "colormap": "viridis",
            "invert_y": True,
        }

    def setup_ui(self):
        """设置UI"""
        # 创建主布局
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)

        # 创建工具栏
        self.create_toolbar()
        main_layout.addWidget(self.toolbar)

        # 创建Matplotlib画布
        self.figure = Figure(figsize=(10, 8), dpi=100)
        self.canvas = FigureCanvas(self.figure)
        main_layout.addWidget(self.canvas)

        # 创建状态栏
        self.create_status_bar()
        main_layout.addWidget(self.status_bar)

        # 初始化图表
        self.init_chart()

        # 设置右键菜单
        self.canvas.setContextMenuPolicy(Qt.CustomContextMenu)
        self.canvas.customContextMenuRequested.connect(self._show_context_menu)

    def create_toolbar(self):
        """创建工具栏"""
        self.toolbar = QToolBar("图表控制")
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        # 添加曲线选择下拉框
        self.toolbar.addWidget(QLabel("选择曲线:"))
        self.curve_combo = QComboBox()
        self.curve_combo.setMinimumWidth(150)
        self.toolbar.addWidget(self.curve_combo)

        # 添加多个曲线选择按钮
        self.multi_curve_btn = QToolButton()
        self.multi_curve_btn.setText("多曲线")
        self.multi_curve_btn.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
        self.multi_curve_btn.setToolButtonStyle(Qt.ToolButtonTextOnly)

        multi_curve_menu = QMenu()
        self.compare_action = QAction("对比显示", self)
        self.overlay_action = QAction("叠加显示", self)
        self.stack_action = QAction("堆叠显示", self)

        multi_curve_menu.addAction(self.compare_action)
        multi_curve_menu.addAction(self.overlay_action)
        multi_curve_menu.addAction(self.stack_action)

        self.multi_curve_btn.setMenu(multi_curve_menu)
        # 连接点击事件到显示菜单的槽函数
        self.multi_curve_btn.clicked.connect(lambda: multi_curve_menu.popup(self.multi_curve_btn.mapToGlobal(self.multi_curve_btn.rect().bottomLeft())))

        self.toolbar.addWidget(self.multi_curve_btn)

        self.toolbar.addSeparator()

        # 添加深度范围控制
        self.toolbar.addWidget(QLabel("深度范围:"))

        self.depth_min_spin = QSpinBox()
        self.depth_min_spin.setRange(0, 10000)
        self.depth_min_spin.setValue(0)
        self.depth_min_spin.setSuffix(" m")
        self.depth_min_spin.setFixedWidth(80)
        self.toolbar.addWidget(self.depth_min_spin)

        self.toolbar.addWidget(QLabel(" - "))

        self.depth_max_spin = QSpinBox()
        self.depth_max_spin.setRange(0, 10000)
        self.depth_max_spin.setValue(5000)
        self.depth_max_spin.setSuffix(" m")
        self.depth_max_spin.setFixedWidth(80)
        self.toolbar.addWidget(self.depth_max_spin)

        self.auto_range_btn = QPushButton("自动范围")
        self.toolbar.addWidget(self.auto_range_btn)

        self.toolbar.addSeparator()

        # 添加交互模式按钮
        self.zoom_btn = QAction("缩放", self)
        self.zoom_btn.setCheckable(True)

        self.pan_btn = QAction("平移", self)
        self.pan_btn.setCheckable(True)

        self.selection_btn = QAction("选择", self)
        self.selection_btn.setCheckable(True)

        self.toolbar.addAction(self.zoom_btn)
        self.toolbar.addAction(self.pan_btn)
        self.toolbar.addAction(self.selection_btn)

        self.toolbar.addSeparator()

        # 添加图表设置按钮
        self.options_btn = QAction("图表设置", self)
        self.toolbar.addAction(self.options_btn)

        # 添加刷新按钮
        self.refresh_btn = QAction("刷新", self)
        self.toolbar.addAction(self.refresh_btn)

        # 添加导出按钮
        self.export_btn = QAction("导出", self)
        self.toolbar.addAction(self.export_btn)

    def create_status_bar(self):
        """创建状态栏"""
        self.status_bar = QWidget()
        status_layout = QHBoxLayout(self.status_bar)
        status_layout.setContentsMargins(5, 2, 5, 2)

        # 深度信息
        self.depth_info_label = QLabel("当前深度: -- m")
        status_layout.addWidget(self.depth_info_label)

        # 曲线值信息
        self.value_info_label = QLabel("曲线值: --")
        status_layout.addWidget(self.value_info_label)

        # 选中区域信息
        self.selection_info_label = QLabel("选中区域: --")
        status_layout.addWidget(self.selection_info_label)

        status_layout.addStretch()

    def init_chart(self):
        """初始化图表"""
        try:
            self.figure.clear()
            self.axes = self.figure.add_subplot(111)
            self.axes.set_title("水平数据可视化")
            self.axes.set_xlabel("值")
            self.axes.set_ylabel("深度 (m)")

            # 设置交互事件
            self.canvas.mpl_connect('motion_notify_event', self._on_mouse_move)
            self.canvas.mpl_connect('button_press_event', self._on_mouse_click)

            # 创建SpanSelector用于区域选择
            self.span_selector = SpanSelector(
                self.axes,
                self._on_range_selected,
                'vertical',
                useblit=True,
                props=dict(alpha=0.3, facecolor='blue')
            )
            self.span_selector.set_active(False)  # 默认不激活

            self.canvas.draw()
        except Exception as e:
            print(f"初始化图表时出错: {e}")

    def update_data(self, well_name, data):
        """更新数据"""
        if data is None or data.empty:
            QMessageBox.warning(self, "警告", "没有可用的数据")
            return

        self.current_well_name = well_name
        self.current_data = data

        # 重置选择状态
        self.selected_range = None
        self.selection_info_label.setText("选中区域: --")

        # 检测深度列
        self.depth_column = self._detect_depth_column(data.columns)

        # 更新曲线选择下拉框
        self.curve_combo.clear()
        if self.depth_column and self.depth_column in data.columns:
            curve_names = [col for col in data.columns if col != self.depth_column]
        else:
            curve_names = list(data.columns)

        self.curve_combo.addItems(curve_names)

        # 更新深度范围
        if not data.empty and self.depth_column and self.depth_column in data.columns:
            try:
                min_depth = int(data[self.depth_column].min())
                max_depth = int(data[self.depth_column].max())

                self.depth_min_spin.setValue(min_depth)
                self.depth_max_spin.setValue(max_depth)

                self.depth_min_spin.setRange(min_depth, max_depth - 10)
                self.depth_max_spin.setRange(min_depth + 10, max_depth)
            except Exception as e:
                print(f"更新深度范围时出错: {e}")

        # 绘制初始图表
        if curve_names:
            self.current_curve = curve_names[0]
            self._on_curve_changed(self.current_curve)

    def _detect_depth_column(self, columns):
        """检测深度列"""
        for col in ['斜深', '井深', 'TVD', 'MD', 'DEPTH']:
            if col in columns:
                return col
        return None

    def setup_connections(self):
        """连接信号和槽"""
        self.curve_combo.currentTextChanged.connect(self._on_curve_changed)
        self.depth_min_spin.valueChanged.connect(self._on_depth_range_changed)
        self.depth_max_spin.valueChanged.connect(self._on_depth_range_changed)
        self.auto_range_btn.clicked.connect(self._on_auto_range)

        self.zoom_btn.triggered.connect(self._on_zoom_mode)
        self.pan_btn.triggered.connect(self._on_pan_mode)
        self.selection_btn.triggered.connect(self._on_selection_mode)

        self.options_btn.triggered.connect(self._on_options)
        self.refresh_btn.triggered.connect(self._on_refresh)
        self.export_btn.triggered.connect(self._on_export)

        self.compare_action.triggered.connect(lambda: self._on_multi_curve("compare"))
        self.overlay_action.triggered.connect(lambda: self._on_multi_curve("overlay"))
        self.stack_action.triggered.connect(lambda: self._on_multi_curve("stack"))
        print("信号槽连接完成")  # 添加日志输出

    def _on_curve_changed(self, curve_name):
        """处理曲线选择变化"""
        if self.current_data is None or self.current_data.empty or curve_name not in self.current_data.columns:
            return

        self.current_curve = curve_name
        self._plot_curve(curve_name)

    def _on_depth_range_changed(self):
        """处理深度范围变化"""
        curve_name = self.curve_combo.currentText()
        if not curve_name or self.current_data is None or self.current_data.empty:
            return

        # 确保最小深度不大于最大深度
        depth_min = self.depth_min_spin.value()
        depth_max = self.depth_max_spin.value()
        if depth_min >= depth_max:
            sender = self.sender()
            if sender == self.depth_min_spin:
                self.depth_max_spin.setValue(depth_min + 10)
            else:
                self.depth_min_spin.setValue(depth_max - 10)
            return

        self._plot_curve(curve_name)

    def _on_auto_range(self):
        """自动设置深度范围"""
        if self.current_data is None or self.current_data.empty or not self.depth_column or self.depth_column not in self.current_data.columns:
            return

        try:
            min_depth = int(self.current_data[self.depth_column].min())
            max_depth = int(self.current_data[self.depth_column].max())

            self.depth_min_spin.setValue(min_depth)
            self.depth_max_spin.setValue(max_depth)
        except Exception as e:
            print(f"自动设置深度范围时出错: {e}")

    def _on_zoom_mode(self, checked):
        """切换缩放模式"""
        self.zoom_mode = checked
        self.pan_mode = False
        self.selection_mode = False

        self.pan_btn.setChecked(False)
        self.selection_btn.setChecked(False)

        self.axes.set_navigate_mode('zoom' if checked else None)
        self.canvas.draw_idle()

    def _on_pan_mode(self, checked):
        """切换平移模式"""
        self.pan_mode = checked
        self.zoom_mode = False
        self.selection_mode = False

        self.zoom_btn.setChecked(False)
        self.selection_btn.setChecked(False)

        self.axes.set_navigate_mode('pan' if checked else None)
        self.canvas.draw_idle()

    def _on_selection_mode(self, checked):
        """切换选择模式"""
        self.selection_mode = checked
        self.zoom_mode = False
        self.pan_mode = False

        self.zoom_btn.setChecked(False)
        self.pan_btn.setChecked(False)

        self.span_selector.set_active(checked)
        self.canvas.draw_idle()

    def _on_range_selected(self, xmin, xmax):
        """处理区域选择"""
        if self.current_data is None or self.current_data.empty or not self.depth_column or not self.current_curve:
            return

        # 获取选中的深度范围
        if self.plot_options["invert_y"]:
            depth_min = min(xmin, xmax)
            depth_max = max(xmin, xmax)
        else:
            depth_min = max(xmin, xmax)
            depth_max = min(xmin, xmax)

        self.selected_range = (depth_min, depth_max)

        # 更新选择信息
        self.selection_info_label.setText(f"选中区域: {depth_min:.2f} - {depth_max:.2f} m")

        # 重新绘制曲线，高亮显示选中区域
        self._plot_curve(self.current_curve)

    def _on_options(self):
        """打开图表设置对话框"""
        if not self.current_curve:
            return

        dialog = DisplayOptionsDialog(
            self.current_well_name,
            self.current_curve,
            self,
            self.plot_options
        )

        if dialog.exec_():
            self.plot_options = dialog.get_options()
            self._plot_curve(self.current_curve)

    def _on_refresh(self):
        """处理刷新按钮点击"""
        if self.current_curve:
            self._plot_curve(self.current_curve)

    def _on_export(self):
        """处理导出按钮点击"""
        if self.current_data is None or self.current_data.empty or self.current_curve is None:
            QMessageBox.warning(self, "警告", "没有数据可供导出")
            return

        # 获取当前显示的数据
        depth_min = self.depth_min_spin.value()
        depth_max = self.depth_max_spin.value()

        if self.depth_column and self.depth_column in self.current_data.columns:
            filtered_data = self.current_data[
                (self.current_data[self.depth_column] >= depth_min) &
                (self.current_data[self.depth_column] <= depth_max)
            ]
        else:
            filtered_data = self.current_data

        # 如果有选中区域，只导出选中区域的数据
        if self.selected_range:
            depth_min, depth_max = self.selected_range
            filtered_data = filtered_data[
                (filtered_data[self.depth_column] >= depth_min) &
                (filtered_data[self.depth_column] <= depth_max)
            ]

        if filtered_data.empty:
            QMessageBox.warning(self, "警告", "没有数据可供导出")
            return

        # 发送导出请求信号
        self.export_requested.emit(self.current_curve, filtered_data)

    def _plot_curve(self, curve_name, ax=None, alpha=None):
        """绘制单条曲线"""
        if self.current_data is None or self.current_data.empty or curve_name not in self.current_data.columns:
            return

        # 如果未传入 ax，则使用默认的 self.axes
        if ax is None:
            ax = self.axes
        else:
            ax.clear()

        # 获取深度范围
        depth_min = self.depth_min_spin.value()
        depth_max = self.depth_max_spin.value()

        # 筛选数据
        if self.depth_column and self.depth_column in self.current_data.columns:
            filtered_data = self.current_data[
                (self.current_data[self.depth_column] >= depth_min) &
                (self.current_data[self.depth_column] <= depth_max)
                ]

            # 应用数据处理选项
            if self.plot_options["normalize"]:
                if not filtered_data[curve_name].empty:
                    try:
                        min_val = filtered_data[curve_name].min()
                        max_val = filtered_data[curve_name].max()
                        if max_val != min_val:
                            filtered_data[curve_name] = (filtered_data[curve_name] - min_val) / (max_val - min_val)
                    except Exception as e:
                        print(f"数据归一化时出错: {e}")

            cmap = plt.get_cmap(self.plot_options["colormap"])
            color_index = list(self.current_data.columns).index(curve_name) / len(self.current_data.columns)
            color = cmap(color_index)

            # 如果未传入 alpha，则使用默认的透明度
            if alpha is None:
                alpha = self.plot_options["opacity"]

            # 绘制曲线
            if self.plot_options["plot_type"] == "曲线图":
                line, = ax.plot(
                    filtered_data[curve_name],
                    filtered_data[self.depth_column],
                    color=color,
                    linewidth=self.plot_options["line_width"],
                    linestyle=self.plot_options["line_style"],
                    alpha=alpha
                )

                # 添加标记
                if self.plot_options["marker"] != "None":
                    line.set_marker(self.plot_options["marker"])
                    line.set_markersize(self.plot_options["marker_size"])

                # 填充区域
                if self.plot_options["fill_between"]:
                    ax.fill_betweenx(
                        filtered_data[self.depth_column],
                        filtered_data[curve_name],
                        alpha=0.3,
                        color=self.plot_options["color"]
                    )

            elif self.plot_options["plot_type"] == "柱状图":
                ax.barh(
                    filtered_data[self.depth_column],
                    filtered_data[curve_name],
                    height=1,
                    color=color,
                    alpha=alpha
                )

            elif self.plot_options["plot_type"] == "散点图":
                ax.scatter(
                    filtered_data[curve_name],
                    filtered_data[self.depth_column],
                    color=color,
                    s=self.plot_options["marker_size"] ** 2,
                    alpha=alpha
                )

            # 设置y轴方向为向下（如果需要）
            if self.plot_options["invert_y"]:
                ax.set_ylim(depth_max, depth_min)
            else:
                ax.set_ylim(depth_min, depth_max)

            ax.set_title(f"{self.current_well_name} - {curve_name}")
            ax.set_xlabel(curve_name)
            ax.set_ylabel("深度 (m)")

            # 设置对数刻度（如果需要）
            if self.plot_options["log_scale"]:
                ax.set_xscale('log')

            # 添加网格线
            if self.plot_options["show_grid"]:
                ax.grid(True, linestyle='--', alpha=0.7)

        if ax == self.axes:
            self.canvas.draw()
        else:
            self.figure.canvas.draw_idle()


    def _on_multi_curve(self, mode):
        """处理多曲线显示"""
        # 修改此处的条件判断
        if self.current_data is None or self.current_data.empty:
            QMessageBox.warning(self, "警告", "没有可用的数据")
            return

        if mode == "compare":
            print("准备进行多曲线 compare 显示")
            try:
                self._plot_multi_curve('compare')
            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

        elif mode == "overlay":
            print("准备进行多曲线 overlay 显示")
            try:
                # 具体的绘制代码
                self._plot_multi_curve('overlay')
            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

        elif mode == "stack":
            print("准备进行多曲线 stack 显示")
            try:
                # 具体的绘制代码
                self._plot_multi_curve('stack')
            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

    def _plot_multi_curve(self, mode):
        """处理多曲线显示"""
        # 修改此处的条件判断
        if self.current_data is None or self.current_data.empty:
            QMessageBox.warning(self, "警告", "没有可用的数据")
            return

        if mode == "compare":
            print("准备进行多曲线 compare 显示")
            try:
                # 清空当前图表
                self.figure.clear()
                self.axes = self.figure.add_subplot(111)
                self.axes.set_title("多曲线对比显示")
                self.axes.set_xlabel("值")
                self.axes.set_ylabel("深度 (m)")

                # 获取所有曲线名称
                curves = [self.curve_combo.itemText(i) for i in range(self.curve_combo.count())]
                for curve in curves:
                    if curve in self.current_data.columns:
                        # 绘制每条曲线
                        self._plot_curve(curve, ax=self.axes)

                # 显示图例
                self.axes.legend()
                self.canvas.draw()

            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

        elif mode == "overlay":
            print("准备进行多曲线 overlay 显示")
            try:
                # 清空当前图表
                self.figure.clear()
                self.axes = self.figure.add_subplot(111)
                self.axes.set_title("多曲线叠加显示")
                self.axes.set_xlabel("值")
                self.axes.set_ylabel("深度 (m)")

                # 获取所有曲线名称
                curves = [self.curve_combo.itemText(i) for i in range(self.curve_combo.count())]
                for curve in curves:
                    if curve in self.current_data.columns:
                        # 绘制每条曲线，设置透明度
                        self._plot_curve(curve, ax=self.axes, alpha=0.5)

                # 显示图例
                self.axes.legend()
                self.canvas.draw()

            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

        elif mode == "stack":
            print("准备进行多曲线 stack 显示")
            try:
                # 清空当前图表
                self.figure.clear()

                # 获取所有曲线名称
                curves = [self.curve_combo.itemText(i) for i in range(self.curve_combo.count())]
                valid_curves = [curve for curve in curves if curve in self.current_data.columns]
                num_curves = len(valid_curves)

                # 为每条曲线创建一个子图
                for i, curve in enumerate(valid_curves):
                    ax = self.figure.add_subplot(num_curves, 1, i + 1)
                    ax.set_title(f"{curve} 堆叠显示")
                    ax.set_xlabel("值")
                    ax.set_ylabel("深度 (m)")

                    # 绘制当前曲线
                    self._plot_curve(curve, ax=ax)

                    # 如果不是最后一个子图，隐藏 x 轴标签
                    if i < num_curves - 1:
                        ax.set_xticklabels([])

                # 调整子图布局
                self.figure.tight_layout()
                self.canvas.draw()

            except Exception as e:
                print(f"绘制多曲线时出错: {e}")

    def _on_mouse_move(self, event):
        """处理鼠标移动事件"""
        pass

    def _on_mouse_click(self, event):
        """处理鼠标点击事件"""
        pass

    def _show_context_menu(self, pos):
        """显示右键菜单"""
        pass
